import java.util.*;
public class CompletelyFair extends Scheduler{
	public void run(){
		check_new();
		while(!queue.isEmpty() || !processes.isEmpty()){
			if(!queue.isEmpty()){
				if(time - queue.get(0).arrival - queue.get(0).wait_time != queue.get(0).running_time)
					queue.get(0).wait_time += time - queue.get(0).last_access;
				if(queue.get(0).last_access == queue.get(0).arrival)
					System.out.println("[Time: " + time + "ms][Process "  + queue.get(0).id + "|Burst Time: " + queue.get(0).burst + "ms|Wait time: " + queue.get(0).wait_time + "ms] is accessing the CPU for the first time");
				else
					System.out.println("[Time: " + time + "ms][Process "  + queue.get(0).id + "|Remaining Burst: " + queue.get(0).burst + "ms|Wait time: " + queue.get(0).wait_time + "ms|Runtime: " + queue.get(0).running_time +"ms] is accessing the CPU");
				while(queue.get(0).burst > 0){
					queue.get(0).burst--;
					queue.get(0).running_time++;
					time++;
					check_new();
				}
				queue.get(0).turnaround_time = time - queue.get(0).arrival;
				turnaround_times.add(queue.get(0).turnaround_time);
				wait_times.add(queue.get(0).wait_time);
	        	System.out.println("[Time: " + time + "ms][Context Switch][Process " + queue.get(0).id + "|Wait Time: " + queue.get(0).wait_time + "ms|Turnaround Time " + (time - queue.get(0).arrival) + "ms] has terminated");
				context_switch();
	        	context_switch_count++;
				queue.remove(0);
				if(!(queue.size() <= 1 || !processes.isEmpty()))
                    check_new();
				Collections.sort(queue, new Runtime_Comparison());
			}
			else{
				time++;
				check_new();
			}
		}
		print_stats();
	}
	public void context_switch(){
		time += 1;
    	context_switch_time += 1;
	}
	public void check_new(){
		while(!processes.isEmpty() && processes.get(0).arrival <= time){
			queue.add(processes.get(0));
			System.out.println("[Time: " + time + "ms][Process " + processes.get(0).id + "|Burst Time: " + processes.get(0).burst + "ms] added to queue");
			processes.remove(0);
		}
		if(!queue.isEmpty()){
			Process p = queue.get(0);
			Collections.sort(queue, new Runtime_Comparison());
			if(queue.get(0) != p){
				for(int i = 0; i < queue.size(); i++){
					if(queue.get(i) == p)
						queue.get(i).last_access = time;
					if(queue.get(i).burst <= 0)
						queue.remove(i);
				}
				if(time != 0){
					queue.get(0).wait_time += time - queue.get(0).last_access;
					if(p.burst != 0){
						System.out.println("[Time: " + time + "ms][Context Switch][Process " + p.id + "|Remaining Burst: " + p.burst + "ms|Runtime: " + p.running_time +"ms] swapped out for [Process " + queue.get(0).id + "|Remaining Burst: " + queue.get(0).burst + "ms|Wait Time: " + queue.get(0).wait_time + "ms|Runtime: " + queue.get(0).running_time + "]");
						if(queue.get(0).last_access == queue.get(0).arrival)
							System.out.println("[Time: " + time + "ms][Process "  + queue.get(0).id + "|Burst Time: " + queue.get(0).burst + "ms|Wait time: " + queue.get(0).wait_time + "ms] is accessing the CPU for the first time");
						else
							System.out.println("[Time: " + time + "ms][Process "  + queue.get(0).id + "|Remaining Burst: " + queue.get(0).burst + "ms|Wait time: " + queue.get(0).wait_time + "ms|Runtime: " + queue.get(0).running_time +"ms] is accessing the CPU");
					}
					else{
						p.turnaround_time = time - p.arrival;
						turnaround_times.add(p.turnaround_time);
						wait_times.add(p.wait_time);
			        	System.out.println("[Time: " + time + "ms][Context Switch][Process " + p.id + "|Wait Time: " + p.wait_time + "ms|Turnaround Time " + (time - p.arrival) + "ms|Runtime: " + p.running_time + "ms] has terminated");
						if(queue.get(0).last_access == queue.get(0).arrival)
							System.out.println("[Time: " + time + "ms][Process "  + queue.get(0).id + "|Burst Time: " + queue.get(0).burst + "ms|Wait time: " + queue.get(0).wait_time + "ms] is accessing the CPU for the first time");
						else
							System.out.println("[Time: " + time + "ms][Process "  + queue.get(0).id + "|Remaining Burst: " + queue.get(0).burst + "ms|Wait time: " + queue.get(0).wait_time + "ms|Runtime: " + queue.get(0).running_time +"ms] is accessing the CPU");
					}
					context_switch();
					context_switch_count++;
				}
			}
		}
	}
}
